package com.ctrip.coverage.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ctrip.coverage.model.dto.TfsScanDto;
import com.ctrip.coverage.model.entity.TfsDifferentFileEntity;
import com.ctrip.coverage.model.entity.TfsFolderEntity;
import com.ctrip.coverage.model.entity.TfsScanEntity;
import com.ctrip.coverage.orm.dao.BaseDaoI;
import com.ctrip.coverage.utils.config.CodelibraryConfig;
import com.ctrip.coverage.utils.config.RCConfig;
import com.ctrip.coverage.utils.enums.TfsFileChangeType;

/**
 * @author sunmx
 */

@Service("tfsService")
public class TfsService {
	@Autowired
	BaseDaoI<TfsFolderEntity> tfsFolderDao;
	@Autowired
	BaseDaoI<TfsScanEntity> tfsScanDao;
	@Autowired
	BaseDaoI<TfsDifferentFileEntity> tfsDifferentFileDao;
	@Autowired
	RCConfig config;
	@Autowired
	CodelibraryConfig codelibraryConfig;
	private static final Logger logger = Logger.getLogger(TfsService.class);

	@Transactional
	public void scanTfs(TfsFolderEntity tfsFolderEntity, TfsScanDto tfsscanDto) throws Exception {
		logger.info("scanTfs:" + ToStringBuilder.reflectionToString(tfsscanDto));
		tfsScanDao.executeHql("delete from TfsScanEntity where startVersion=" + tfsscanDto.getStartVersion() + "and endVersion=" + tfsscanDto.getEndVersion() + "and tfsFolder.id="
				+ tfsFolderEntity.getId());

		TfsScanEntity scanEntity = new TfsScanEntity();
		Set<TfsDifferentFileEntity> differentset = scanDifferent(tfsFolderEntity, tfsscanDto, scanEntity);

		int filecount = getFileNumberOfEndVersion(tfsFolderEntity, tfsscanDto);

		scanEntity.setScanTime(new Date());
		scanEntity.setDescription(tfsscanDto.getDescription());
		scanEntity.setStartVersion(tfsscanDto.getStartVersion());
		scanEntity.setEndVersion(tfsscanDto.getEndVersion());
		scanEntity.setTfsDifferentFile(differentset);
		scanEntity.setTfsFolder(tfsFolderEntity);
		scanEntity.setTotalFileCount(filecount);
		int allchangecount = differentset.size();
		int addfilecount = 0;
		int deletefilecount = 0;
		int modifyfilecount = 0;
		for (TfsDifferentFileEntity file : differentset) {
			if (file.getChangeType() == TfsFileChangeType.ADD) {
				addfilecount++;
			} else if (file.getChangeType() == TfsFileChangeType.DELETE) {
				deletefilecount++;
			} else if (file.getChangeType() == TfsFileChangeType.MODIFY) {
				modifyfilecount++;
			}
			//持久化differentfiles
			tfsDifferentFileDao.save(file);
		}
		scanEntity.setAllChangedFileCount(allchangecount);
		scanEntity.setAddFileCount(addfilecount);
		scanEntity.setDeleteFileCount(deletefilecount);
		scanEntity.setModifyFileCount(modifyfilecount);
		if (filecount == 0) {
			scanEntity.setChangeRate(0);
		} else {
			scanEntity.setChangeRate((float) allchangecount / (float) filecount);
		}
		tfsScanDao.save(scanEntity);
	}

	/**
	 * 检查具体的差异
	 * @param tfsscan
	 * @param folder
	 * @return
	 * @throws Exception
	 */
	private Set<TfsDifferentFileEntity> scanDifferent(TfsFolderEntity tfsFolderEntity, TfsScanDto tfsscanDto, TfsScanEntity scan){

		Set<TfsDifferentFileEntity> thefileset = new HashSet<TfsDifferentFileEntity>();

		Runtime rt = Runtime.getRuntime();
		//Process proc = rt.exec("cmd.exe /c start /b diff.bat D:/TFS1/SelectedDepot/Source/Dev/MerchantWeb/Dev/1.0/Merchant.Web c80006 c81110 cn1\\gxshi YLPabs95",null,new File("C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\"));
		Process proc;
		try {
			proc = rt.exec("cmd.exe /c start /b diff.bat \"" + tfsFolderEntity.getServerPath() + "\" " + tfsscanDto.getStartVersion() + " " + tfsscanDto.getEndVersion() + " "
					+ config.getTfsUserName() + " " + config.getTfsPassword(), null, new File(codelibraryConfig.getTfsVcPath()));
			 proc.getOutputStream().close();

				InputStreamReader inputStreamReader = new InputStreamReader(proc.getInputStream());
				BufferedReader br = new BufferedReader(inputStreamReader);
				String line = "";
				Boolean modifyTcn = false;

				StringBuffer sb = new StringBuffer();
				TfsDifferentFileEntity thefile = null;
				int t = 0;
				while ((line = br.readLine()) != null) {
					if (line.startsWith("File:") && line.endsWith(".cs")) {
						modifyTcn = true;
						thefile = new TfsDifferentFileEntity();
						thefile.setChangeType(TfsFileChangeType.MODIFY);
						thefile.setTfsScan(scan);

						Pattern p = Pattern.compile(" .*(cs$)");
						Matcher m = p.matcher(line);

						if (m.find()) {
							thefile.setPath(m.group().trim());
						}
						thefileset.add(thefile);
					} else if (line.contains("file found only in:") && line.contains(".cs")) {
						Pattern p = Pattern.compile("\\$.*;");
						Matcher m = p.matcher(line);

						if (line.endsWith("C" + tfsscanDto.getStartVersion() + "]")) {
							thefile = new TfsDifferentFileEntity();
							thefile.setChangeType(TfsFileChangeType.DELETE);
							thefile.setTfsScan(scan);
							if (m.find()) {
								String a = m.group().replaceAll(";", "");
								String b[] = line.split(".cs");
								thefile.setPath(a + "/" + b[0] + ".cs");
								thefile.setModifyContent(a + "/" + b[0] + ".cs");
							}
							thefileset.add(thefile);

						} else if (line.endsWith("C" + tfsscanDto.getEndVersion() + "]")) {
							thefile = new TfsDifferentFileEntity();
							thefile.setChangeType(TfsFileChangeType.ADD);
							thefile.setTfsScan(scan);
							if (m.find()) {
								String a = m.group().replaceAll(";", "");
								String b[] = line.split(".cs");
								thefile.setPath(a + "/" + b[0] + ".cs");
								thefile.setModifyContent(a + "/" + b[0] + ".cs");
							}
							thefileset.add(thefile);
						}

					}
					if (modifyTcn == true) {
						if (line.startsWith("===")) {
							t++;
						}
						if (t > 1) {
							modifyTcn = false;
							sb.append(line + "\r\n");
							t = 0;
							thefile.setModifyContent(sb.toString());
						} else {
							sb.append(line + "\r\n");
						}
					}
				}
				br.close();
				inputStreamReader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
       
		return thefileset;
	}

	/**
	 * 扫表文件夹在目标版本下的文件数量（不包含文件夹）
	 * @param tfsscan
	 * @param folder
	 * @return
	 * @throws Exception 
	 */
	private int getFileNumberOfEndVersion(TfsFolderEntity tfsFolderEntity, TfsScanDto tfsscanDto) throws Exception {
		int filescount = 0;
		Runtime rt = Runtime.getRuntime();
		//		Process proc = rt.exec("cmd.exe /c start /b diff.bat $/TestSolution/InterfaceTest/mytest 34286 34289 cn1\\zzhang willeyzhangMs5",null,new File("C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\"));
		Process proc = rt
				.exec("cmd.exe /c start /b dir.bat " + tfsFolderEntity.getServerPath() + " " + tfsscanDto.getEndVersion() + " " + config.getTfsUserName() + " "
						+ config.getTfsPassword(), null, new File(codelibraryConfig.getTfsVcPath()));
		proc.getOutputStream().close();
		InputStreamReader inputStreamReader = new InputStreamReader(proc.getInputStream());
		BufferedReader br = new BufferedReader(inputStreamReader);
		String line = "";
		while ((line = br.readLine()) != null) {
			if (line.endsWith(".cs")) {
				filescount++;
			}
		}
		return filescount;
	}

	@Transactional
	public void tfsScanSolution(TfsFolderEntity tfsFolderEntityStart, TfsFolderEntity tfsFolderEntityEnd) throws Exception {
		TfsScanEntity scanEntity = new TfsScanEntity();
		tfsScanDao.executeHql("delete from TfsScanEntity where startVersion='" + tfsFolderEntityStart.getName() + "' and endVersion='" + tfsFolderEntityEnd.getName()
				+ "' and tfsFolder.id=" + tfsFolderEntityEnd.getParentId());

		Set<TfsDifferentFileEntity> differentset = scanDifferentSolution(tfsFolderEntityStart, tfsFolderEntityEnd, scanEntity);
		TfsFolderEntity tfsFolderParent = tfsFolderDao.get(" from TfsFolderEntity where id=" + tfsFolderEntityEnd.getParentId());

		int filecount = getFileNumberOfEndSolution(tfsFolderEntityEnd);

		scanEntity.setScanTime(new Date());
		scanEntity.setStartVersion(tfsFolderEntityStart.getName());
		scanEntity.setEndVersion(tfsFolderEntityEnd.getName());
		scanEntity.setTfsDifferentFile(differentset);
		scanEntity.setTfsFolder(tfsFolderParent);
		scanEntity.setTotalFileCount(filecount);
		int allchangecount = differentset.size();
		int addfilecount = 0;
		int deletefilecount = 0;
		int modifyfilecount = 0;
		for (TfsDifferentFileEntity file : differentset) {
			if (file.getChangeType() == TfsFileChangeType.ADD) {
				addfilecount++;
			} else if (file.getChangeType() == TfsFileChangeType.DELETE) {
				deletefilecount++;
			} else if (file.getChangeType() == TfsFileChangeType.MODIFY) {
				modifyfilecount++;
			}
			//持久化differentfiles
			tfsDifferentFileDao.save(file);
		}
		scanEntity.setAllChangedFileCount(allchangecount);
		scanEntity.setAddFileCount(addfilecount);
		scanEntity.setDeleteFileCount(deletefilecount);
		scanEntity.setModifyFileCount(modifyfilecount);
		if (filecount == 0) {
			scanEntity.setChangeRate(0);
		} else {
			scanEntity.setChangeRate((float) allchangecount / (float) filecount);
		}
		tfsScanDao.save(scanEntity);
	}

	private Set<TfsDifferentFileEntity> scanDifferentSolution(TfsFolderEntity tfsFolderEntityStart, TfsFolderEntity tfsFolderEntityEnd, TfsScanEntity scan) throws IOException {
		Set<TfsDifferentFileEntity> thefileset = new HashSet<TfsDifferentFileEntity>();
		Runtime rt = Runtime.getRuntime();
		Process proc = rt.exec("cmd.exe /c start /b diffSolution.bat \"" + tfsFolderEntityStart.getServerPath() + "\" " + tfsFolderEntityEnd.getServerPath(), null,
				new File(codelibraryConfig.getTfsVcPath()));
		proc.getOutputStream().close();
		InputStreamReader inputStreamReader = new InputStreamReader(proc.getInputStream());
		BufferedReader br = new BufferedReader(inputStreamReader);
		String line = "";
		Boolean modifyTcn = false;

		StringBuffer sb= new StringBuffer();
		TfsDifferentFileEntity thefile = null;
		int t = 0;
		while ((line = br.readLine()) != null) {

			if (line.startsWith("File:") && line.endsWith(".cs")) {
				modifyTcn = true;
				thefile = new TfsDifferentFileEntity();
				thefile.setChangeType(TfsFileChangeType.MODIFY);
				thefile.setTfsScan(scan);

				Pattern p = Pattern.compile(" .*(cs$)");
				Matcher m = p.matcher(line);

				if (m.find()) {
					thefile.setPath(m.group().trim());
				}
				thefileset.add(thefile);
			} else if (line.contains("file found only in:") && line.contains(".cs ")) {
				Pattern p = Pattern.compile("[CDEFG]:.*]$");
				Matcher m = p.matcher(line);

				if (line.contains(tfsFolderEntityStart.getName())) {
					thefile = new TfsDifferentFileEntity();
					thefile.setChangeType(TfsFileChangeType.DELETE);
					thefile.setTfsScan(scan);
					if (m.find()) {
						String a = m.group().toString();
						String b = a.replace("]", "");
						String c[] = line.split(".cs");
						//						String a = m.group().replaceAll(";", "");
						//						String b[] = line.split(".cs");
						thefile.setPath(b + "\\" + c[0] + ".cs");
						thefile.setModifyContent(b + "\\" + c[0] + ".cs");
					}
					thefileset.add(thefile);

				} else if (line.contains(tfsFolderEntityEnd.getName())) {
					thefile = new TfsDifferentFileEntity();
					thefile.setChangeType(TfsFileChangeType.ADD);
					thefile.setTfsScan(scan);
					if (m.find()) {
						String a = m.group().toString();
						String b = a.replace("]", "");
						String c[] = line.split(".cs");
						thefile.setPath(b + "\\" + c[0] + ".cs");
						thefile.setModifyContent(b + "\\" + c[0] + ".cs");
					}
					thefileset.add(thefile);
				}

			}
			if (modifyTcn == true) {
				
				if (line.startsWith("===")) {
					t++;
				}
				if (t > 1) {
					modifyTcn = false;
					sb.append(line + "\r\n");
					t = 0;
					String s=new String(sb.toString().getBytes(),"gbk");
					thefile.setModifyContent(s);
					sb.delete(0, sb.length());
				} else {
					sb.append(line + "\r\n");
				}
			}
		}
		br.close();
		inputStreamReader.close();
		return thefileset;

	}

	/**
	 * 扫表文件夹在目标版本下的文件数量（不包含文件夹）
	 * @param tfsscan
	 * @param folder
	 * @return
	 * @throws Exception 
	 */
	private int getFileNumberOfEndSolution(TfsFolderEntity tfsFolderEntityEnd) throws Exception {
		int filescount = 0;
		Runtime rt = Runtime.getRuntime();
		Process proc = rt.exec("cmd.exe /c start /b dirSolution.bat " + tfsFolderEntityEnd.getServerPath(), null, new File(codelibraryConfig.getTfsVcPath()));
		proc.getOutputStream().close();
		InputStreamReader inputStreamReader = new InputStreamReader(proc.getInputStream());
		BufferedReader br = new BufferedReader(inputStreamReader);
		String line = "";
		while ((line = br.readLine()) != null) {
			if (line.endsWith(".cs")) {
				filescount++;
			}
		}
		return filescount;
	}
}
